package cn.harperDog.multithreading;

import com.sun.jmx.remote.internal.ArrayQueue;

import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author hua
 * @description
 * @date 2022/3/4
 *
 * 生产者和消费者
 */
public class ProviderConsumer<T> {
    //队列长度
    private int length;
    //队列
    private Queue<T> queue;
    //锁
    ReentrantLock lock = new ReentrantLock();
    Condition providerCondition = lock.newCondition();
    Condition consumerCondition = lock.newCondition();

    public ProviderConsumer(int length){
        this.length = length;
        this.queue = new LinkedList<>();
    }

    public void provide(T product){
        try {
            lock.lock();

            while(queue.size() >= length){
                providerCondition.await();
            }

            queue.add(product);
            System.out.println("product"+product);
            consumerCondition.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public T consum(){
        try {
            lock.lock();
            while (queue.isEmpty()){
                consumerCondition.await();
            }
            T product = queue.remove();
            System.out.println("consum"+product);
            providerCondition.signal();
            return product;
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
           lock.unlock();
        }
        return null;
    }

    public static void main(String[] args) {
        try {
            ProviderConsumer<Integer> providerConsumer = new ProviderConsumer(2);
            for (int i=0;i<5;i++){
                Thread p = new Thread(() -> {
                    providerConsumer.provide(1);
                });
                p.start();
                //此处不能有join，这里hang主主线程后，下面的创建消费者线程就不会执行了
//                p.join();
            }

            for (int i=0;i<5;i++){
                Thread c = new Thread(() -> {
                    providerConsumer.consum();
                });
                c.start();
//                c.join();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
